package io.gitee.mingbaobaba.apijson.querycondition.query.dao.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import io.gitee.mingbaobaba.apijson.querycondition.query.conditions.ApiJsonQuery;
import io.gitee.mingbaobaba.apijson.querycondition.query.dao.DwQueryDao;
import io.gitee.mingbaobaba.apijson.querycondition.query.dao.support.AccessTokenProvider;
import io.gitee.mingbaobaba.apijson.querycondition.query.dao.support.CachingAccessTokenProvider;
import io.gitee.mingbaobaba.apijson.querycondition.query.dao.support.EndpointResolver;
import io.gitee.mingbaobaba.apijson.querycondition.query.dao.support.OkHttpClientFactory;
import io.gitee.mingbaobaba.apijson.querycondition.query.exception.ConditionException;
import io.gitee.mingbaobaba.apijson.querycondition.query.properties.ApiJsonQueryProperties;
import lombok.extern.slf4j.Slf4j;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okhttp3.ResponseBody;
import org.apache.commons.lang3.StringUtils;

import java.io.IOException;
import java.util.Map;
import java.util.Random;

/**
 * <p>默认基于http方式获取数据接口实现</p>
 *
 * @author yingsheng.ye
 * @version 1.0.0
 * @since 2023/6/27 20:40
 */
@Slf4j
public class DefaultHttpApiJsonQueryDaoImpl implements DwQueryDao {
    private static final MediaType JSON_MEDIA_TYPE = MediaType.parse("application/json; charset=utf-8");

    private final ApiJsonQueryProperties dataWarehouseProperties;
    private final OkHttpClient httpClient;
    private final AccessTokenProvider accessTokenProvider;
    private final Random rand = new Random();

    public DefaultHttpApiJsonQueryDaoImpl(ApiJsonQueryProperties dataWarehouseProperties) {
        this(dataWarehouseProperties, OkHttpClientFactory.create(dataWarehouseProperties));
    }

    public DefaultHttpApiJsonQueryDaoImpl(ApiJsonQueryProperties dataWarehouseProperties, OkHttpClient httpClient) {
        this(dataWarehouseProperties, httpClient, new CachingAccessTokenProvider(dataWarehouseProperties, httpClient));
    }

    public DefaultHttpApiJsonQueryDaoImpl(ApiJsonQueryProperties dataWarehouseProperties,
                                          OkHttpClient httpClient,
                                          AccessTokenProvider accessTokenProvider) {
        this.dataWarehouseProperties = dataWarehouseProperties;
        this.httpClient = httpClient;
        this.accessTokenProvider = accessTokenProvider;
    }

    @Override
    public String getData(Map<String, Object> params, ApiJsonQuery query) {
        String url = loadBalanceUrl(dataWarehouseProperties.getServiceUrl());
        String jsonParam = JSON.toJSONString(params);
        RequestBody body = RequestBody.create(jsonParam, JSON_MEDIA_TYPE);
        Request request = new Request.Builder()
                .url(url)
                .addHeader("Authorization", accessTokenProvider.getBearerToken())
                .addHeader("biSigns", query.getBiSigns())
                .post(body)
                .build();

        try (Response response = httpClient.newCall(request).execute()) {
            if (!response.isSuccessful()) {
                throw new ConditionException("调用接口返回异常:" + response.message());
            }
            String bodyString = readBody(response.body());
            logRequest("查询服务", url, query, jsonParam, bodyString);
            JSONObject data = resultToObject(bodyString);
            return JSON.toJSONString(data);
        } catch (IOException ex) {
            throw new ConditionException("调用查询服务失败", ex);
        }
    }

    private void logRequest(String tag, String url, Object biSignsSource, String requestBody, String responseBody) {
        if (!log.isDebugEnabled()) {
            return;
        }
        String biSigns;
        if (biSignsSource instanceof ApiJsonQuery) {
            biSigns = ((ApiJsonQuery) biSignsSource).getBiSigns();
        } else {
            biSigns = String.valueOf(biSignsSource);
        }
        log.debug("\n---------------------------------------------------------------\n" +
                        "{}地址：{}\n业务标识：{}\n请求参数：{}\n响应结果：{}\n---------------------------------------------------------------",
                tag, url, biSigns, requestBody, responseBody);
    }

    private String readBody(ResponseBody body) throws IOException {
        if (body == null) {
            throw new ConditionException("查询服务返回空响应体");
        }
        return body.string();
    }

    /**
     * 结果提取转换
     *
     * @param res 返回结果
     * @return JSONObject
     */
    private JSONObject resultToObject(String res) {
        if (StringUtils.isBlank(res)) {
            throw new ConditionException("调用查询服务返回为空");
        }
        //解析token
        JSONObject jsonObject = JSON.parseObject(res);
        Integer code = jsonObject.getInteger("code");
        if (code == null) {
            return extractData(jsonObject);
        }
        int successCode = 20000;
        if (successCode != code) {
            throw new ConditionException("调用查询服务异常：" + jsonObject.getString("message"));
        }
        return extractData(jsonObject);
    }

    private JSONObject extractData(JSONObject jsonObject) {
        JSONObject data = jsonObject.getJSONObject("data");
        return data == null ? jsonObject : data;
    }

    /**
     * 获取服务请求地址
     *
     * @return 地址
     */
    private String loadBalanceUrl(String url) {
        return EndpointResolver.pickOne(url, rand);
    }
}
